/*BHEADER**********************************************************************
 * Copyright (c) 2017,  Lawrence Livermore National Security, LLC.
 * Produced at the Lawrence Livermore National Laboratory.
 * Written by Ulrike Yang (yang11@llnl.gov) et al. CODE-LLNL-738-322.
 * This file is part of AMG.  See files README and COPYRIGHT for details.
 *
 * AMG is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License (as published by the Free
 * Software Foundation) version 2.1 dated February 1999.
 *
 * This software is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF MERCHANTIBILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the terms and conditions of the
 * GNU General Public License for more details.
 *
 ***********************************************************************EHEADER*/





/******************************************************************************
 *
 * ParAMG functions
 *
 *****************************************************************************/

#include "_hypre_parcsr_ls.h"
#include "par_amg.h"
#include <assert.h>

/*--------------------------------------------------------------------------
 * hypre_BoomerAMGCreate
 *--------------------------------------------------------------------------*/

void *
hypre_BoomerAMGCreate()
{
   hypre_ParAMGData  *amg_data;

   /* setup params */
   HYPRE_Int      max_levels;
   HYPRE_Int      max_coarse_size;
   HYPRE_Int      min_coarse_size;
   HYPRE_Real   strong_threshold;
   HYPRE_Real   max_row_sum;
   HYPRE_Real   trunc_factor;
   HYPRE_Real   agg_trunc_factor;
   HYPRE_Real   agg_P12_trunc_factor;
   HYPRE_Real   jacobi_trunc_threshold;
   HYPRE_Real   S_commpkg_switch;
   HYPRE_Real   CR_rate;
   HYPRE_Real   CR_strong_th;
   HYPRE_Int      interp_type;
   HYPRE_Int      sep_weight;
   HYPRE_Int      coarsen_type;
   HYPRE_Int      measure_type;
   HYPRE_Int      setup_type;
   HYPRE_Int      P_max_elmts;
   HYPRE_Int 	    num_functions;
   HYPRE_Int 	    nodal, nodal_levels, nodal_diag;
   HYPRE_Int 	    num_paths;
   HYPRE_Int 	    agg_num_levels;
   HYPRE_Int      agg_interp_type;
   HYPRE_Int      agg_P_max_elmts;
   HYPRE_Int      agg_P12_max_elmts;
   HYPRE_Int      post_interp_type;
   HYPRE_Int 	    seq_threshold;
   HYPRE_Int        redundant;

   /* solve params */
   HYPRE_Int      min_iter;
   HYPRE_Int      max_iter;
   HYPRE_Int      cycle_type;    
 
   HYPRE_Real   tol;

   HYPRE_Int      num_sweeps;  
   HYPRE_Int      relax_down;   
   HYPRE_Int      relax_up;   
   HYPRE_Int      relax_coarse;   
   HYPRE_Int      relax_order;   
   HYPRE_Real   relax_wt;
   HYPRE_Real   outer_wt;
   HYPRE_Real   nongalerkin_tol;

   HYPRE_Int cheby_order;
   HYPRE_Int cheby_eig_est;
   HYPRE_Int cheby_variant;
   HYPRE_Int cheby_scale;
   HYPRE_Real cheby_eig_ratio;

   HYPRE_Int        additive;
   HYPRE_Int        mult_additive;
   HYPRE_Int        simple;
   HYPRE_Int        add_last_lvl;
   HYPRE_Real   add_trunc_factor;
   HYPRE_Int      add_P_max_elmts;
   HYPRE_Int      add_rlx_type;
   HYPRE_Real   add_rlx_wt;

   /* log info */
   HYPRE_Int      num_iterations;
   HYPRE_Int      cum_num_iterations;

   /* output params */
   HYPRE_Int      print_level;
   HYPRE_Int      logging;
   /* HYPRE_Int      cycle_op_count; */
   char     log_file_name[256];
   HYPRE_Int      debug_flag;

   char     plot_file_name[251] = {0};

   /*-----------------------------------------------------------------------
    * Setup default values for parameters
    *-----------------------------------------------------------------------*/

   /* setup params */
   max_levels = 25;
   max_coarse_size = 9;
   min_coarse_size = 0;
   seq_threshold = 0;
   redundant = 0;
   strong_threshold = 0.25;
   max_row_sum = 0.9;
   trunc_factor = 0.0;
   agg_trunc_factor = 0.0;
   agg_P12_trunc_factor = 0.0;
   jacobi_trunc_threshold = 0.01;
   S_commpkg_switch = 1.0;
   interp_type = 0;
   sep_weight = 0;
   coarsen_type = 10;
   interp_type = 6;
   measure_type = 0;
   setup_type = 1;
   P_max_elmts = 4;
   agg_P_max_elmts = 0;
   agg_P12_max_elmts = 0;
   num_functions = 1;
   nodal = 0;
   nodal_levels = max_levels;
   nodal_diag = 0;
   num_paths = 1;
   agg_num_levels = 0;
   post_interp_type = 0;
   agg_interp_type = 4;
   
   /* solve params */
   min_iter  = 0;
   max_iter  = 20;
   cycle_type = 1;
   tol = 1.0e-7;

   num_sweeps = 1;
   relax_down = 13;
   relax_up = 14;
   relax_coarse = 9;
   relax_order = 0;
   relax_wt = 1.0;
   outer_wt = 1.0;

   cheby_order = 2;
   cheby_variant = 0;
   cheby_scale = 1;
   cheby_eig_est = 10;
   cheby_eig_ratio = .3;

   additive = -1;
   mult_additive = -1;
   simple = -1;
   add_last_lvl = -1;
   add_trunc_factor = 0.0;
   add_P_max_elmts = 0;
   add_rlx_type = 18;
   add_rlx_wt = 1.0;

   /* log info */
   num_iterations = 0;
   cum_num_iterations = 0;

   /* output params */
   print_level = 0;
   logging = 0;
   hypre_sprintf(log_file_name, "%s", "amg.out.log");
   /* cycle_op_count = 0; */
   debug_flag = 0;

   nongalerkin_tol = 0.0;

   /*HYPRE_ANNOTATION_BEGIN("BoomerAMG.create");*/
   
   /*-----------------------------------------------------------------------
    * Create the hypre_ParAMGData structure and return
    *-----------------------------------------------------------------------*/

   amg_data = hypre_CTAlloc(hypre_ParAMGData, 1);

   hypre_ParAMGDataMaxLevels(amg_data) =  max_levels;
   hypre_ParAMGDataUserCoarseRelaxType(amg_data) = 9;
   hypre_ParAMGDataUserRelaxType(amg_data) = -1;
   hypre_ParAMGDataUserNumSweeps(amg_data) = -1;
   hypre_ParAMGDataUserRelaxWeight(amg_data) = relax_wt;
   hypre_ParAMGDataOuterWt(amg_data) = outer_wt;
   hypre_BoomerAMGSetMaxCoarseSize(amg_data, max_coarse_size);
   hypre_BoomerAMGSetMinCoarseSize(amg_data, min_coarse_size);
   hypre_BoomerAMGSetStrongThreshold(amg_data, strong_threshold);
   hypre_BoomerAMGSetMaxRowSum(amg_data, max_row_sum);
   hypre_BoomerAMGSetTruncFactor(amg_data, trunc_factor);
   hypre_BoomerAMGSetAggTruncFactor(amg_data, agg_trunc_factor);
   hypre_BoomerAMGSetAggP12TruncFactor(amg_data, agg_P12_trunc_factor);
   hypre_BoomerAMGSetJacobiTruncThreshold(amg_data, jacobi_trunc_threshold);
   hypre_BoomerAMGSetSCommPkgSwitch(amg_data, S_commpkg_switch);
   hypre_BoomerAMGSetSepWeight(amg_data, sep_weight);
   hypre_BoomerAMGSetMeasureType(amg_data, measure_type);
   hypre_BoomerAMGSetCoarsenType(amg_data, coarsen_type);
   hypre_BoomerAMGSetInterpType(amg_data, interp_type);
   hypre_BoomerAMGSetSetupType(amg_data, setup_type);
   hypre_BoomerAMGSetPMaxElmts(amg_data, P_max_elmts);
   hypre_BoomerAMGSetAggPMaxElmts(amg_data, agg_P_max_elmts);
   hypre_BoomerAMGSetAggP12MaxElmts(amg_data, agg_P12_max_elmts);
   hypre_BoomerAMGSetNumFunctions(amg_data, num_functions);
   hypre_BoomerAMGSetNodal(amg_data, nodal);
   hypre_BoomerAMGSetNodalLevels(amg_data, nodal_levels);
   hypre_BoomerAMGSetNodal(amg_data, nodal_diag);
   hypre_BoomerAMGSetNumPaths(amg_data, num_paths);
   hypre_BoomerAMGSetAggNumLevels(amg_data, agg_num_levels);
   hypre_BoomerAMGSetAggInterpType(amg_data, agg_interp_type);
   hypre_BoomerAMGSetPostInterpType(amg_data, post_interp_type);

   hypre_BoomerAMGSetMinIter(amg_data, min_iter);
   hypre_BoomerAMGSetMaxIter(amg_data, max_iter);
   hypre_BoomerAMGSetCycleType(amg_data, cycle_type);
   hypre_BoomerAMGSetTol(amg_data, tol); 
   hypre_BoomerAMGSetNumSweeps(amg_data, num_sweeps);
   hypre_BoomerAMGSetCycleRelaxType(amg_data, relax_down, 1);
   hypre_BoomerAMGSetCycleRelaxType(amg_data, relax_up, 2);
   hypre_BoomerAMGSetCycleRelaxType(amg_data, relax_coarse, 3);
   hypre_BoomerAMGSetRelaxOrder(amg_data, relax_order);
   hypre_BoomerAMGSetRelaxWt(amg_data, relax_wt);
   hypre_BoomerAMGSetOuterWt(amg_data, outer_wt);

   hypre_BoomerAMGSetChebyOrder(amg_data, cheby_order);
   hypre_BoomerAMGSetChebyFraction(amg_data, cheby_eig_ratio);
   hypre_BoomerAMGSetChebyEigEst(amg_data, cheby_eig_est);
   hypre_BoomerAMGSetChebyVariant(amg_data, cheby_variant);
   hypre_BoomerAMGSetChebyScale(amg_data, cheby_scale);

   hypre_BoomerAMGSetNumIterations(amg_data, num_iterations);

   hypre_BoomerAMGSetAdditive(amg_data, additive);
   hypre_BoomerAMGSetMultAdditive(amg_data, mult_additive);
   hypre_BoomerAMGSetSimple(amg_data, simple);
   hypre_BoomerAMGSetMultAddPMaxElmts(amg_data, add_P_max_elmts);
   hypre_BoomerAMGSetMultAddTruncFactor(amg_data, add_trunc_factor);
   hypre_BoomerAMGSetAddRelaxType(amg_data, add_rlx_type);
   hypre_BoomerAMGSetAddRelaxWt(amg_data, add_rlx_wt);
   hypre_ParAMGDataAddLastLvl(amg_data) = add_last_lvl;
   hypre_ParAMGDataLambda(amg_data) = NULL;
   hypre_ParAMGDataXtilde(amg_data) = NULL;
   hypre_ParAMGDataRtilde(amg_data) = NULL;
   hypre_ParAMGDataDinv(amg_data) = NULL;

#ifdef CUMNUMIT
   hypre_ParAMGDataCumNumIterations(amg_data) = cum_num_iterations;
#endif
   hypre_BoomerAMGSetPrintLevel(amg_data, print_level);
   hypre_BoomerAMGSetLogging(amg_data, logging);
   hypre_BoomerAMGSetPrintFileName(amg_data, log_file_name); 
   hypre_BoomerAMGSetDebugFlag(amg_data, debug_flag);
   hypre_BoomerAMGSetRestriction(amg_data, 0);

   hypre_ParAMGDataAArray(amg_data) = NULL;
   hypre_ParAMGDataPArray(amg_data) = NULL;
   hypre_ParAMGDataRArray(amg_data) = NULL;
   hypre_ParAMGDataCFMarkerArray(amg_data) = NULL;
   hypre_ParAMGDataVtemp(amg_data)  = NULL;
   hypre_ParAMGDataRtemp(amg_data)  = NULL;
   hypre_ParAMGDataPtemp(amg_data)  = NULL;
   hypre_ParAMGDataZtemp(amg_data)  = NULL;
   hypre_ParAMGDataFArray(amg_data) = NULL;
   hypre_ParAMGDataUArray(amg_data) = NULL;
   hypre_ParAMGDataDofFunc(amg_data) = NULL;
   hypre_ParAMGDataDofFuncArray(amg_data) = NULL;
   hypre_ParAMGDataDofPointArray(amg_data) = NULL;
   hypre_ParAMGDataDofPointArray(amg_data) = NULL;
   hypre_ParAMGDataPointDofMapArray(amg_data) = NULL;
   hypre_ParAMGDataL1Norms(amg_data) = NULL;
  
   /* Stuff for Chebyshev smoothing */
   hypre_ParAMGDataMaxEigEst(amg_data) = NULL;
   hypre_ParAMGDataMinEigEst(amg_data) = NULL;
   hypre_ParAMGDataChebyDS(amg_data) = NULL;
   hypre_ParAMGDataChebyCoefs(amg_data) = NULL;

   /* for redundant coarse grid solve */
   hypre_ParAMGDataSeqThreshold(amg_data) = seq_threshold;
   hypre_ParAMGDataRedundant(amg_data) = redundant;
   hypre_ParAMGDataCoarseSolver(amg_data) = NULL;
   hypre_ParAMGDataACoarse(amg_data) = NULL;
   hypre_ParAMGDataFCoarse(amg_data) = NULL;
   hypre_ParAMGDataUCoarse(amg_data) = NULL;
   hypre_ParAMGDataNewComm(amg_data) = hypre_MPI_COMM_NULL;

   /* for Gaussian elimination coarse grid solve */
   hypre_ParAMGDataAMat(amg_data) = NULL;
   hypre_ParAMGDataBVec(amg_data) = NULL;
   hypre_ParAMGDataCommInfo(amg_data) = NULL;

   hypre_ParAMGDataNonGalerkinTol(amg_data) = nongalerkin_tol;
   hypre_ParAMGDataNonGalTolArray(amg_data) = NULL;

   hypre_ParAMGDataRAP2(amg_data) = 0;
   hypre_ParAMGDataKeepTranspose(amg_data) = 0;

   /*HYPRE_ANNOTATION_END("BoomerAMG.create");*/
   
   return (void *) amg_data;
}

/*--------------------------------------------------------------------------
 * hypre_BoomerAMGDestroy
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGDestroy( void *data )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
   HYPRE_Int num_levels = hypre_ParAMGDataNumLevels(amg_data);
   void *amg = hypre_ParAMGDataCoarseSolver(amg_data);
   MPI_Comm new_comm = hypre_ParAMGDataNewComm(amg_data);
   HYPRE_Int i;
   HYPRE_Int *grid_relax_type = hypre_ParAMGDataGridRelaxType(amg_data);

   /*HYPRE_ANNOTATION_BEGIN("BoomerAMG.destroy");*/
   
   if (hypre_ParAMGDataMaxEigEst(amg_data))
   {
      hypre_TFree(hypre_ParAMGDataMaxEigEst(amg_data));
      hypre_ParAMGDataMaxEigEst(amg_data) = NULL;
   }
   if (hypre_ParAMGDataMinEigEst(amg_data))
   {
      hypre_TFree(hypre_ParAMGDataMinEigEst(amg_data));
      hypre_ParAMGDataMinEigEst(amg_data) = NULL;
   }
   if (hypre_ParAMGDataNumGridSweeps(amg_data))
   {
      hypre_TFree (hypre_ParAMGDataNumGridSweeps(amg_data));
      hypre_ParAMGDataNumGridSweeps(amg_data) = NULL; 
   }
   if (grid_relax_type)
   {
      HYPRE_Int num_levels = hypre_ParAMGDataNumLevels(amg_data);
      hypre_TFree (hypre_ParAMGDataGridRelaxType(amg_data));
      hypre_ParAMGDataGridRelaxType(amg_data) = NULL; 
   }
   if (hypre_ParAMGDataRelaxWeight(amg_data))
   {
      hypre_TFree (hypre_ParAMGDataRelaxWeight(amg_data));
      hypre_ParAMGDataRelaxWeight(amg_data) = NULL; 
   }
   if (hypre_ParAMGDataOmega(amg_data))
   {
      hypre_TFree (hypre_ParAMGDataOmega(amg_data));
      hypre_ParAMGDataOmega(amg_data) = NULL; 
   }
   if (hypre_ParAMGDataNonGalTolArray(amg_data))
   {
      hypre_TFree (hypre_ParAMGDataNonGalTolArray(amg_data));
      hypre_ParAMGDataNonGalTolArray(amg_data) = NULL; 
   }
   if (hypre_ParAMGDataDofFunc(amg_data))
   {
      hypre_TFree (hypre_ParAMGDataDofFunc(amg_data));
      hypre_ParAMGDataDofFunc(amg_data) = NULL; 
   }
   if (hypre_ParAMGDataGridRelaxPoints(amg_data))
   {
      for (i=0; i < 4; i++)
   	hypre_TFree (hypre_ParAMGDataGridRelaxPoints(amg_data)[i]);
      hypre_TFree (hypre_ParAMGDataGridRelaxPoints(amg_data));
      hypre_ParAMGDataGridRelaxPoints(amg_data) = NULL; 
   }
   for (i=1; i < num_levels; i++)
   {
	hypre_ParVectorDestroy(hypre_ParAMGDataFArray(amg_data)[i]);
	hypre_ParVectorDestroy(hypre_ParAMGDataUArray(amg_data)[i]);

        if (hypre_ParAMGDataAArray(amg_data)[i])
           hypre_ParCSRMatrixDestroy(hypre_ParAMGDataAArray(amg_data)[i]);

        if (hypre_ParAMGDataPArray(amg_data)[i-1])
           hypre_ParCSRMatrixDestroy(hypre_ParAMGDataPArray(amg_data)[i-1]);

	hypre_TFree(hypre_ParAMGDataCFMarkerArray(amg_data)[i-1]);
   }

   if (hypre_ParAMGDataLambda(amg_data))
      hypre_ParCSRMatrixDestroy(hypre_ParAMGDataLambda(amg_data));

   if (hypre_ParAMGDataAtilde(amg_data))
   {
      hypre_ParCSRMatrix *Atilde = hypre_ParAMGDataAtilde(amg_data);
      hypre_CSRMatrixDestroy(hypre_ParCSRMatrixDiag(Atilde));
      hypre_CSRMatrixDestroy(hypre_ParCSRMatrixOffd(Atilde));
      hypre_TFree (Atilde);
   }

   if (hypre_ParAMGDataXtilde(amg_data))
      hypre_ParVectorDestroy(hypre_ParAMGDataXtilde(amg_data));

   if (hypre_ParAMGDataRtilde(amg_data))
      hypre_ParVectorDestroy(hypre_ParAMGDataRtilde(amg_data));

   if (hypre_ParAMGDataL1Norms(amg_data))
   {
      for (i=0; i < num_levels; i++)
         if (hypre_ParAMGDataL1Norms(amg_data)[i])
           hypre_TFree(hypre_ParAMGDataL1Norms(amg_data)[i]);
      hypre_TFree(hypre_ParAMGDataL1Norms(amg_data));
   }

   if (hypre_ParAMGDataChebyCoefs(amg_data))
   {
      for (i=0; i < num_levels; i++)
         if (hypre_ParAMGDataChebyCoefs(amg_data)[i])
           hypre_TFree(hypre_ParAMGDataChebyCoefs(amg_data)[i]);
      hypre_TFree(hypre_ParAMGDataChebyCoefs(amg_data));
   }

   if (hypre_ParAMGDataChebyDS(amg_data))
   {
      for (i=0; i < num_levels; i++)
         if (hypre_ParAMGDataChebyDS(amg_data)[i])
           hypre_TFree(hypre_ParAMGDataChebyDS(amg_data)[i]);
      hypre_TFree(hypre_ParAMGDataChebyDS(amg_data));
   }

   if (hypre_ParAMGDataDinv(amg_data))
      hypre_TFree(hypre_ParAMGDataDinv(amg_data));

   /* see comments in par_coarsen.c regarding special case for CF_marker */
   if (num_levels == 1)
   {
      hypre_TFree(hypre_ParAMGDataCFMarkerArray(amg_data)[0]);
   }
   hypre_ParVectorDestroy(hypre_ParAMGDataVtemp(amg_data));
   hypre_TFree(hypre_ParAMGDataFArray(amg_data));
   hypre_TFree(hypre_ParAMGDataUArray(amg_data));
   hypre_TFree(hypre_ParAMGDataAArray(amg_data));
   hypre_TFree(hypre_ParAMGDataPArray(amg_data));
   hypre_TFree(hypre_ParAMGDataCFMarkerArray(amg_data));
   if (hypre_ParAMGDataRtemp(amg_data))
      hypre_ParVectorDestroy(hypre_ParAMGDataRtemp(amg_data));
   if (hypre_ParAMGDataPtemp(amg_data))
      hypre_ParVectorDestroy(hypre_ParAMGDataPtemp(amg_data));
   if (hypre_ParAMGDataZtemp(amg_data))
      hypre_ParVectorDestroy(hypre_ParAMGDataZtemp(amg_data));

   if (hypre_ParAMGDataDofFuncArray(amg_data))
   {
      for (i=1; i < num_levels; i++)
	 hypre_TFree(hypre_ParAMGDataDofFuncArray(amg_data)[i]);
      hypre_TFree(hypre_ParAMGDataDofFuncArray(amg_data));
      hypre_ParAMGDataDofFuncArray(amg_data) = NULL;
   }
   if (hypre_ParAMGDataRestriction(amg_data))
   {
      hypre_TFree(hypre_ParAMGDataRArray(amg_data));
      hypre_ParAMGDataRArray(amg_data) = NULL;
   }
   if (hypre_ParAMGDataDofPointArray(amg_data))
   {
      for (i=0; i < num_levels; i++)
	 hypre_TFree(hypre_ParAMGDataDofPointArray(amg_data)[i]);
      hypre_TFree(hypre_ParAMGDataDofPointArray(amg_data));
      hypre_ParAMGDataDofPointArray(amg_data) = NULL;
   }
   if (hypre_ParAMGDataPointDofMapArray(amg_data))
   {
      for (i=0; i < num_levels; i++)
	 hypre_TFree(hypre_ParAMGDataPointDofMapArray(amg_data)[i]);
      hypre_TFree(hypre_ParAMGDataPointDofMapArray(amg_data));
      hypre_ParAMGDataPointDofMapArray(amg_data) = NULL;
   }
   if ( hypre_ParAMGDataResidual(amg_data) ) {
      /* jfp: was... hypre_TFree( hypre_ParAMGDataResidual(amg_data) );*/
      hypre_ParVectorDestroy( hypre_ParAMGDataResidual(amg_data) );
      hypre_ParAMGDataResidual(amg_data) = NULL;
   }

   if (amg) hypre_BoomerAMGDestroy(amg);

   if (hypre_ParAMGDataACoarse(amg_data))
      hypre_ParCSRMatrixDestroy(hypre_ParAMGDataACoarse(amg_data));

   if (hypre_ParAMGDataUCoarse(amg_data))
      hypre_ParVectorDestroy(hypre_ParAMGDataUCoarse(amg_data));

   if (hypre_ParAMGDataFCoarse(amg_data))
      hypre_ParVectorDestroy(hypre_ParAMGDataFCoarse(amg_data));

   if (hypre_ParAMGDataAMat(amg_data)) hypre_TFree(hypre_ParAMGDataAMat(amg_data));
   if (hypre_ParAMGDataBVec(amg_data)) hypre_TFree(hypre_ParAMGDataBVec(amg_data));
   if (hypre_ParAMGDataCommInfo(amg_data)) hypre_TFree(hypre_ParAMGDataCommInfo(amg_data));

   if (new_comm != hypre_MPI_COMM_NULL) 
   {
       hypre_MPI_Comm_free (&new_comm);
   }
   hypre_TFree(amg_data);

   /*HYPRE_ANNOTATION_END("BoomerAMG.destroy");*/
   
   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Routines to set the setup phase parameters
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetRestriction( void *data,
                            HYPRE_Int   restr_par )
{
	hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   hypre_ParAMGDataRestriction(amg_data) = restr_par;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetMaxLevels( void *data,
                          HYPRE_Int   max_levels )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
   HYPRE_Int old_max_levels;
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (max_levels < 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   old_max_levels = hypre_ParAMGDataMaxLevels(amg_data);
   if (old_max_levels < max_levels)
   {
      HYPRE_Real *relax_weight, *omega, *nongal_tol_array;
      HYPRE_Real relax_wt, outer_wt, nongalerkin_tol;
      HYPRE_Int i;
      relax_weight = hypre_ParAMGDataRelaxWeight(amg_data);
      if (relax_weight)
      {
         relax_wt = hypre_ParAMGDataUserRelaxWeight(amg_data);
         relax_weight = hypre_TReAlloc(relax_weight, HYPRE_Real, max_levels);
         for (i=old_max_levels; i < max_levels; i++)
            relax_weight[i] = relax_wt;
         hypre_ParAMGDataRelaxWeight(amg_data) = relax_weight;
      }
      omega = hypre_ParAMGDataOmega(amg_data);
      if (omega)
      {
         outer_wt = hypre_ParAMGDataOuterWt(amg_data);
         omega = hypre_TReAlloc(omega, HYPRE_Real, max_levels);
         for(i=old_max_levels; i < max_levels; i++)
            omega[i] = outer_wt;
         hypre_ParAMGDataOmega(amg_data) = omega;
      }
      nongal_tol_array = hypre_ParAMGDataNonGalTolArray(amg_data);
      if (nongal_tol_array)
      {
         nongalerkin_tol = hypre_ParAMGDataNonGalerkinTol(amg_data);
         nongal_tol_array = hypre_TReAlloc(nongal_tol_array, HYPRE_Real, max_levels);
         for(i=old_max_levels; i < max_levels; i++)
            nongal_tol_array[i] = nongalerkin_tol;
         hypre_ParAMGDataNonGalTolArray(amg_data) = nongal_tol_array;
      }
   }
   hypre_ParAMGDataMaxLevels(amg_data) = max_levels;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetMaxLevels( void *data,
                             HYPRE_Int *  max_levels )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *max_levels = hypre_ParAMGDataMaxLevels(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetMaxCoarseSize( void *data,
                          HYPRE_Int   max_coarse_size )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (max_coarse_size < 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataMaxCoarseSize(amg_data) = max_coarse_size;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetMaxCoarseSize( void *data,
                             HYPRE_Int *  max_coarse_size )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *max_coarse_size = hypre_ParAMGDataMaxCoarseSize(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetMinCoarseSize( void *data,
                          HYPRE_Int   min_coarse_size )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (min_coarse_size < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataMinCoarseSize(amg_data) = min_coarse_size;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetMinCoarseSize( void *data,
                             HYPRE_Int *  min_coarse_size )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *min_coarse_size = hypre_ParAMGDataMinCoarseSize(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetSeqThreshold( void *data,
                          HYPRE_Int   seq_threshold )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (seq_threshold < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataSeqThreshold(amg_data) = seq_threshold;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetSeqThreshold( void *data,
                             HYPRE_Int *  seq_threshold )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *seq_threshold = hypre_ParAMGDataSeqThreshold(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetRedundant( void *data,
                          HYPRE_Int   redundant )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }

   if (redundant < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataRedundant(amg_data) = redundant;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetRedundant( void *data,
                             HYPRE_Int *  redundant )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }

   *redundant = hypre_ParAMGDataRedundant(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetStrongThreshold( void     *data,
                                HYPRE_Real    strong_threshold )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (strong_threshold < 0 || strong_threshold > 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataStrongThreshold(amg_data) = strong_threshold;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetStrongThreshold( void     *data,
                                HYPRE_Real *  strong_threshold )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *strong_threshold = hypre_ParAMGDataStrongThreshold(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetMaxRowSum( void     *data,
                          HYPRE_Real    max_row_sum )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (max_row_sum <= 0 || max_row_sum > 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataMaxRowSum(amg_data) = max_row_sum;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetMaxRowSum( void     *data,
                          HYPRE_Real *  max_row_sum )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *max_row_sum = hypre_ParAMGDataMaxRowSum(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetTruncFactor( void     *data,
                            HYPRE_Real    trunc_factor )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (trunc_factor < 0 || trunc_factor >= 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataTruncFactor(amg_data) = trunc_factor;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetTruncFactor( void     *data,
                            HYPRE_Real *  trunc_factor )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *trunc_factor = hypre_ParAMGDataTruncFactor(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetPMaxElmts( void     *data,
                            HYPRE_Int    P_max_elmts )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (P_max_elmts < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataPMaxElmts(amg_data) = P_max_elmts;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetPMaxElmts( void     *data,
                            HYPRE_Int *  P_max_elmts )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *P_max_elmts = hypre_ParAMGDataPMaxElmts(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetJacobiTruncThreshold( void     *data,
                            HYPRE_Real    jacobi_trunc_threshold )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (jacobi_trunc_threshold < 0 || jacobi_trunc_threshold >= 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataJacobiTruncThreshold(amg_data) = jacobi_trunc_threshold;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetJacobiTruncThreshold( void     *data,
                            HYPRE_Real *  jacobi_trunc_threshold )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *jacobi_trunc_threshold = hypre_ParAMGDataJacobiTruncThreshold(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetPostInterpType( void     *data,
                                  HYPRE_Int    post_interp_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (post_interp_type < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataPostInterpType(amg_data) = post_interp_type;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetPostInterpType( void     *data,
                                  HYPRE_Int  * post_interp_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *post_interp_type = hypre_ParAMGDataPostInterpType(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetSCommPkgSwitch( void     *data,
                                  HYPRE_Real    S_commpkg_switch )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   hypre_ParAMGDataSCommPkgSwitch(amg_data) = S_commpkg_switch;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetSCommPkgSwitch( void     *data,
                                  HYPRE_Real *  S_commpkg_switch )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *S_commpkg_switch = hypre_ParAMGDataSCommPkgSwitch(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetInterpType( void     *data,
                           HYPRE_Int       interp_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 


   if (interp_type < 0 || interp_type > 25)

   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataInterpType(amg_data) = interp_type;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetInterpType( void     *data,
                           HYPRE_Int *     interp_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *interp_type = hypre_ParAMGDataInterpType(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetSepWeight( void     *data,
                           HYPRE_Int       sep_weight )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   hypre_ParAMGDataSepWeight(amg_data) = sep_weight;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetMinIter( void     *data,
                        HYPRE_Int       min_iter )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   hypre_ParAMGDataMinIter(amg_data) = min_iter;

   return hypre_error_flag;
} 

HYPRE_Int
hypre_BoomerAMGGetMinIter( void     *data,
                        HYPRE_Int *     min_iter )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *min_iter = hypre_ParAMGDataMinIter(amg_data);

   return hypre_error_flag;
} 

HYPRE_Int
hypre_BoomerAMGSetMaxIter( void     *data,
                        HYPRE_Int     max_iter )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (max_iter < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataMaxIter(amg_data) = max_iter;

   return hypre_error_flag;
} 

HYPRE_Int
hypre_BoomerAMGGetMaxIter( void     *data,
                        HYPRE_Int *   max_iter )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *max_iter = hypre_ParAMGDataMaxIter(amg_data);

   return hypre_error_flag;
} 

HYPRE_Int
hypre_BoomerAMGSetCoarsenType( void  *data,
                          HYPRE_Int    coarsen_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   hypre_ParAMGDataCoarsenType(amg_data) = coarsen_type;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetCoarsenType( void  *data,
                          HYPRE_Int *  coarsen_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *coarsen_type = hypre_ParAMGDataCoarsenType(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetMeasureType( void  *data,
                            HYPRE_Int    measure_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   hypre_ParAMGDataMeasureType(amg_data) = measure_type;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetMeasureType( void  *data,
                            HYPRE_Int *  measure_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *measure_type = hypre_ParAMGDataMeasureType(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetSetupType( void  *data,
                             HYPRE_Int    setup_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   hypre_ParAMGDataSetupType(amg_data) = setup_type;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetSetupType( void  *data,
                             HYPRE_Int  *  setup_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *setup_type = hypre_ParAMGDataSetupType(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetCycleType( void  *data,
                          HYPRE_Int    cycle_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (cycle_type < 0 || cycle_type > 2)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataCycleType(amg_data) = cycle_type;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetCycleType( void  *data,
                          HYPRE_Int *  cycle_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *cycle_type = hypre_ParAMGDataCycleType(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetTol( void     *data,
                    HYPRE_Real    tol  )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (tol < 0 || tol > 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   hypre_ParAMGDataTol(amg_data) = tol;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetTol( void     *data,
                    HYPRE_Real *  tol  )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   *tol = hypre_ParAMGDataTol(amg_data);

   return hypre_error_flag;
}

/* The "Get" function for SetNumSweeps is GetCycleNumSweeps. */
HYPRE_Int
hypre_BoomerAMGSetNumSweeps( void     *data,
                              HYPRE_Int      num_sweeps )
{
   HYPRE_Int i;
   HYPRE_Int *num_grid_sweeps;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (num_sweeps < 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   if (hypre_ParAMGDataNumGridSweeps(amg_data) == NULL)
       hypre_ParAMGDataNumGridSweeps(amg_data) = hypre_CTAlloc(HYPRE_Int,4);
       
   num_grid_sweeps = hypre_ParAMGDataNumGridSweeps(amg_data);

   for (i=0; i < 3; i++)
      num_grid_sweeps[i] = num_sweeps;
   num_grid_sweeps[3] = 1;

   hypre_ParAMGDataUserNumSweeps(amg_data) = num_sweeps;

   return hypre_error_flag;
}
 
HYPRE_Int
hypre_BoomerAMGSetCycleNumSweeps( void     *data,
                                  HYPRE_Int      num_sweeps,
                                  HYPRE_Int      k )
{
   HYPRE_Int i;
   HYPRE_Int *num_grid_sweeps;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 

   if (num_sweeps < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   if (k < 1 || k > 3)
   {
      hypre_error_in_arg(3);
      return hypre_error_flag;
   }

   if (hypre_ParAMGDataNumGridSweeps(amg_data) == NULL)
   {
       num_grid_sweeps = hypre_CTAlloc(HYPRE_Int,4);
       for (i=0; i < 4; i++)
	  num_grid_sweeps[i] = 1;
       hypre_ParAMGDataNumGridSweeps(amg_data) = num_grid_sweeps;
   }
       
   hypre_ParAMGDataNumGridSweeps(amg_data)[k] = num_sweeps;

   return hypre_error_flag;
}
 
HYPRE_Int
hypre_BoomerAMGGetCycleNumSweeps( void     *data,
                                  HYPRE_Int *    num_sweeps,
                                  HYPRE_Int      k )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (k < 1 || k > 3)
   {
      hypre_error_in_arg(3);
      return hypre_error_flag;
   }

   if (hypre_ParAMGDataNumGridSweeps(amg_data) == NULL)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }
       
   *num_sweeps = hypre_ParAMGDataNumGridSweeps(amg_data)[k];

   return hypre_error_flag;
}
 
HYPRE_Int
hypre_BoomerAMGSetNumGridSweeps( void     *data,
                              HYPRE_Int      *num_grid_sweeps )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (!num_grid_sweeps)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   if (hypre_ParAMGDataNumGridSweeps(amg_data))
      hypre_TFree(hypre_ParAMGDataNumGridSweeps(amg_data));
   hypre_ParAMGDataNumGridSweeps(amg_data) = num_grid_sweeps;

   return hypre_error_flag;
}
 
HYPRE_Int
hypre_BoomerAMGGetNumGridSweeps( void     *data,
                              HYPRE_Int    ** num_grid_sweeps )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *num_grid_sweeps = hypre_ParAMGDataNumGridSweeps(amg_data);

   return hypre_error_flag;
}
 
/* The "Get" function for SetRelaxType is GetCycleRelaxType. */
HYPRE_Int
hypre_BoomerAMGSetRelaxType( void     *data,
                              HYPRE_Int      relax_type )
{
   HYPRE_Int i;
   HYPRE_Int *grid_relax_type;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (relax_type < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   if (hypre_ParAMGDataGridRelaxType(amg_data) == NULL)
       hypre_ParAMGDataGridRelaxType(amg_data) = hypre_CTAlloc(HYPRE_Int,4);
   grid_relax_type = hypre_ParAMGDataGridRelaxType(amg_data);

   for (i=0; i < 3; i++)
      grid_relax_type[i] = relax_type;
   grid_relax_type[3] = 9;
   hypre_ParAMGDataUserCoarseRelaxType(amg_data) = 9;
   hypre_ParAMGDataUserRelaxType(amg_data) = relax_type;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetCycleRelaxType( void     *data,
                                  HYPRE_Int      relax_type,
                                  HYPRE_Int      k )
{
   HYPRE_Int i;
   HYPRE_Int *grid_relax_type;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (k < 1 || k > 3)
   {
      hypre_error_in_arg(3);
      return hypre_error_flag;
   }
   if (relax_type < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   if (hypre_ParAMGDataGridRelaxType(amg_data) == NULL)
   {
      grid_relax_type = hypre_CTAlloc(HYPRE_Int,4);
      for (i=0; i < 3; i++)
         grid_relax_type[i] = 3;
      grid_relax_type[3] = 9;
      hypre_ParAMGDataGridRelaxType(amg_data) = grid_relax_type;
   }
      
   hypre_ParAMGDataGridRelaxType(amg_data)[k] = relax_type;
   if (k == 3)
      hypre_ParAMGDataUserCoarseRelaxType(amg_data) = relax_type;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetCycleRelaxType( void     *data,
                                  HYPRE_Int    * relax_type,
                                  HYPRE_Int      k )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (k < 1 || k > 3)
   {
      hypre_error_in_arg(3);
      return hypre_error_flag;
   }

   if (hypre_ParAMGDataGridRelaxType(amg_data) == NULL)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }
      
   *relax_type = hypre_ParAMGDataGridRelaxType(amg_data)[k];

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetRelaxOrder( void     *data,
                              HYPRE_Int       relax_order)
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataRelaxOrder(amg_data) = relax_order;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetRelaxOrder( void     *data,
                              HYPRE_Int     * relax_order)
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *relax_order = hypre_ParAMGDataRelaxOrder(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetGridRelaxType( void     *data,
                              HYPRE_Int      *grid_relax_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (!grid_relax_type)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   if (hypre_ParAMGDataGridRelaxType(amg_data))
      hypre_TFree(hypre_ParAMGDataGridRelaxType(amg_data));
   hypre_ParAMGDataGridRelaxType(amg_data) = grid_relax_type;
   hypre_ParAMGDataUserCoarseRelaxType(amg_data) = grid_relax_type[3];

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetGridRelaxType( void     *data,
                              HYPRE_Int    ** grid_relax_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *grid_relax_type = hypre_ParAMGDataGridRelaxType(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetGridRelaxPoints( void     *data,
                                HYPRE_Int      **grid_relax_points )
{
   HYPRE_Int i;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (!grid_relax_points)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   if (hypre_ParAMGDataGridRelaxPoints(amg_data))
   {
      for (i=0; i < 4; i++)
   	hypre_TFree (hypre_ParAMGDataGridRelaxPoints(amg_data)[i]);
      hypre_TFree(hypre_ParAMGDataGridRelaxPoints(amg_data));
   }
   hypre_ParAMGDataGridRelaxPoints(amg_data) = grid_relax_points; 

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetGridRelaxPoints( void     *data,
                                HYPRE_Int    *** grid_relax_points )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *grid_relax_points = hypre_ParAMGDataGridRelaxPoints(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetRelaxWeight( void     *data,
                               HYPRE_Real   *relax_weight )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (!relax_weight)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   if (hypre_ParAMGDataRelaxWeight(amg_data))
      hypre_TFree(hypre_ParAMGDataRelaxWeight(amg_data));
   hypre_ParAMGDataRelaxWeight(amg_data) = relax_weight;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetRelaxWeight( void     *data,
                               HYPRE_Real ** relax_weight )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *relax_weight = hypre_ParAMGDataRelaxWeight(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetRelaxWt( void     *data,
                           HYPRE_Real    relax_weight )
{
   HYPRE_Int i, num_levels;
   HYPRE_Real *relax_weight_array;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   num_levels = hypre_ParAMGDataMaxLevels(amg_data);
   if (hypre_ParAMGDataRelaxWeight(amg_data) == NULL)
      hypre_ParAMGDataRelaxWeight(amg_data) = hypre_CTAlloc(HYPRE_Real,num_levels);
                     
   relax_weight_array = hypre_ParAMGDataRelaxWeight(amg_data);
   for (i=0; i < num_levels; i++)
      relax_weight_array[i] = relax_weight;

   hypre_ParAMGDataUserRelaxWeight(amg_data) = relax_weight;
   
   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetLevelRelaxWt( void    *data,
                                HYPRE_Real   relax_weight,
                                HYPRE_Int      level )
{
   HYPRE_Int i, num_levels;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   num_levels = hypre_ParAMGDataMaxLevels(amg_data);
   if (level > num_levels-1 || level < 0) 
   {
      hypre_error_in_arg(3);
      return hypre_error_flag;
   }
   if (hypre_ParAMGDataRelaxWeight(amg_data) == NULL)
   {
      hypre_ParAMGDataRelaxWeight(amg_data) = hypre_CTAlloc(HYPRE_Real,num_levels);
      for (i=0; i < num_levels; i++)
         hypre_ParAMGDataRelaxWeight(amg_data)[i] = 1.0;
   }
               
   hypre_ParAMGDataRelaxWeight(amg_data)[level] = relax_weight;
   
   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetLevelRelaxWt( void    *data,
                                HYPRE_Real * relax_weight,
                                HYPRE_Int      level )
{
   HYPRE_Int num_levels;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   num_levels = hypre_ParAMGDataMaxLevels(amg_data);
   if (level > num_levels-1 || level < 0) 
   {
      hypre_error_in_arg(3);
      return hypre_error_flag;
   }
   if (hypre_ParAMGDataRelaxWeight(amg_data) == NULL)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }
               
   *relax_weight = hypre_ParAMGDataRelaxWeight(amg_data)[level];
   
   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetOmega( void     *data,
                         HYPRE_Real   *omega )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (!omega)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   if (hypre_ParAMGDataOmega(amg_data))
      hypre_TFree(hypre_ParAMGDataOmega(amg_data));
   hypre_ParAMGDataOmega(amg_data) = omega;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetOmega( void     *data,
                         HYPRE_Real ** omega )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *omega = hypre_ParAMGDataOmega(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetOuterWt( void     *data,
                           HYPRE_Real    omega )
{
   HYPRE_Int i, num_levels;
   HYPRE_Real *omega_array;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   num_levels = hypre_ParAMGDataMaxLevels(amg_data);
   if (hypre_ParAMGDataOmega(amg_data) == NULL)
      hypre_ParAMGDataOmega(amg_data) = hypre_CTAlloc(HYPRE_Real,num_levels);
                     
   omega_array = hypre_ParAMGDataOmega(amg_data);
   for (i=0; i < num_levels; i++)
      omega_array[i] = omega;
   hypre_ParAMGDataOuterWt(amg_data) = omega;
 
   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetLevelOuterWt( void    *data,
                                HYPRE_Real   omega,
                                HYPRE_Int      level )
{
   HYPRE_Int i, num_levels;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   num_levels = hypre_ParAMGDataMaxLevels(amg_data);
   if (level > num_levels-1) 
   {
      hypre_error_in_arg(3);
      return hypre_error_flag;
   }
   if (hypre_ParAMGDataOmega(amg_data) == NULL)
   {
      hypre_ParAMGDataOmega(amg_data) = hypre_CTAlloc(HYPRE_Real,num_levels);
      for (i=0; i < num_levels; i++)
         hypre_ParAMGDataOmega(amg_data)[i] = 1.0;
   }
               
   hypre_ParAMGDataOmega(amg_data)[level] = omega;
   
   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetLevelOuterWt( void    *data,
                                HYPRE_Real * omega,
                                HYPRE_Int      level )
{
   HYPRE_Int num_levels;
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   num_levels = hypre_ParAMGDataMaxLevels(amg_data);
   if (level > num_levels-1) 
   {
      hypre_error_in_arg(3);
      return hypre_error_flag;
   }
   if (hypre_ParAMGDataOmega(amg_data) == NULL)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }
               
   *omega = hypre_ParAMGDataOmega(amg_data)[level];
   
   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetLogging( void     *data,
                            HYPRE_Int       logging )
{
   /* This function should be called before Setup.  Logging changes
      may require allocation or freeing of arrays, which is presently
      only done there.
      It may be possible to support logging changes at other times,
      but there is little need.
   */
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataLogging(amg_data) = logging;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetLogging( void     *data,
                            HYPRE_Int     * logging )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *logging = hypre_ParAMGDataLogging(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetPrintLevel( void     *data,
                        HYPRE_Int print_level )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataPrintLevel(amg_data) = print_level;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetPrintLevel( void     *data,
                        HYPRE_Int * print_level )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *print_level =  hypre_ParAMGDataPrintLevel(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetPrintFileName( void       *data,
                               const char *print_file_name )
{
   hypre_ParAMGData  *amg_data =  (hypre_ParAMGData*)data;
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if( strlen(print_file_name) > 256 )
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 

   hypre_sprintf(hypre_ParAMGDataLogFileName(amg_data), "%s", print_file_name);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetPrintFileName( void       *data,
                                 char ** print_file_name )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_sprintf( *print_file_name, "%s", hypre_ParAMGDataLogFileName(amg_data) );

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetNumIterations( void    *data,
                              HYPRE_Int      num_iterations )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataNumIterations(amg_data) = num_iterations;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetDebugFlag( void     *data,
                          HYPRE_Int       debug_flag )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataDebugFlag(amg_data) = debug_flag;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetDebugFlag( void     *data,
                          HYPRE_Int     * debug_flag )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *debug_flag = hypre_ParAMGDataDebugFlag(amg_data);

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Routines to set the problem data parameters
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetNumFunctions( void     *data,
                            HYPRE_Int       num_functions )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (num_functions < 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataNumFunctions(amg_data) = num_functions;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetNumFunctions( void     *data,
                            HYPRE_Int     * num_functions )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *num_functions = hypre_ParAMGDataNumFunctions(amg_data);

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicate whether to use nodal systems function
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetNodal( void     *data,
                          HYPRE_Int    nodal )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataNodal(amg_data) = nodal;

   return hypre_error_flag;
}
/*--------------------------------------------------------------------------
 * Indicate number of levels for nodal coarsening
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetNodalLevels( void     *data,
                          HYPRE_Int    nodal_levels )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataNodalLevels(amg_data) = nodal_levels;

   return hypre_error_flag;
}


/*--------------------------------------------------------------------------
 * Indicate how to treat diag for primary matrix with  nodal systems function
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetNodalDiag( void     *data,
                          HYPRE_Int    nodal )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataNodalDiag(amg_data) = nodal;

   return hypre_error_flag;
}
/*--------------------------------------------------------------------------
 * Indicate the degree of aggressive coarsening
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetNumPaths( void     *data,
                            HYPRE_Int       num_paths )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (num_paths < 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataNumPaths(amg_data) = num_paths;

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicates the number of levels of aggressive coarsening
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetAggNumLevels( void     *data,
                            HYPRE_Int       agg_num_levels )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (agg_num_levels < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataAggNumLevels(amg_data) = agg_num_levels;

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicates the interpolation used with aggressive coarsening
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetAggInterpType( void     *data,
                            HYPRE_Int       agg_interp_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (agg_interp_type < 0 || agg_interp_type > 4)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataAggInterpType(amg_data) = agg_interp_type;

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicates max number of elements per row for aggressive coarsening 
 * interpolation
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetAggPMaxElmts( void     *data,
                            HYPRE_Int       agg_P_max_elmts )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (agg_P_max_elmts < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataAggPMaxElmts(amg_data) = agg_P_max_elmts;

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicates max number of elements per row for smoothed 
 * interpolation in mult-additive or simple method
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetMultAddPMaxElmts( void     *data,
                            HYPRE_Int       add_P_max_elmts )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (add_P_max_elmts < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataMultAddPMaxElmts(amg_data) = add_P_max_elmts;

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicates Relaxtion Type for Additive Cycle
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetAddRelaxType( void     *data,
                            HYPRE_Int       add_rlx_type )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataAddRelaxType(amg_data) = add_rlx_type;

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicates Relaxation Weight for Additive Cycle
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetAddRelaxWt( void     *data,
                            HYPRE_Real       add_rlx_wt )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataAddRelaxWt(amg_data) = add_rlx_wt;

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicates max number of elements per row for 1st stage of aggressive
 * coarsening two-stage interpolation
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetAggP12MaxElmts( void     *data,
                            HYPRE_Int       agg_P12_max_elmts )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (agg_P12_max_elmts < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataAggP12MaxElmts(amg_data) = agg_P12_max_elmts;

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicates truncation factor for aggressive coarsening interpolation
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetAggTruncFactor( void     *data,
                            HYPRE_Real  agg_trunc_factor )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (agg_trunc_factor < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataAggTruncFactor(amg_data) = agg_trunc_factor;

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicates the truncation factor for smoothed interpolation when using
 * mult-additive or simple method
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetMultAddTruncFactor( void     *data,
                            HYPRE_Real      add_trunc_factor )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (add_trunc_factor < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataMultAddTruncFactor(amg_data) = add_trunc_factor;

   return hypre_error_flag;
}

/*--------------------------------------------------------------------------
 * Indicates truncation factor for 1 stage of aggressive coarsening
 * two stage interpolation
 *--------------------------------------------------------------------------*/

HYPRE_Int
hypre_BoomerAMGSetAggP12TruncFactor( void     *data,
                            HYPRE_Real  agg_P12_trunc_factor )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (agg_P12_trunc_factor < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataAggP12TruncFactor(amg_data) = agg_P12_trunc_factor;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetNumPoints( void     *data,
                          HYPRE_Int       num_points )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataNumPoints(amg_data) = num_points;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetDofFunc( void     *data,
                           HYPRE_Int      *dof_func )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_TFree(hypre_ParAMGDataDofFunc(amg_data));
   hypre_ParAMGDataDofFunc(amg_data) = dof_func;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetPointDofMap( void     *data,
                         HYPRE_Int      *point_dof_map )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_TFree(hypre_ParAMGDataPointDofMap(amg_data));
   hypre_ParAMGDataPointDofMap(amg_data) = point_dof_map;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetDofPoint( void     *data,
                         HYPRE_Int      *dof_point )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_TFree(hypre_ParAMGDataDofPoint(amg_data));
   hypre_ParAMGDataDofPoint(amg_data) = dof_point;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetNumIterations( void     *data,
                              HYPRE_Int      *num_iterations )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *num_iterations = hypre_ParAMGDataNumIterations(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetCumNumIterations( void     *data,
                                    HYPRE_Int      *cum_num_iterations )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
#ifdef CUMNUMIT
   *cum_num_iterations = hypre_ParAMGDataCumNumIterations(amg_data);
#endif

   return hypre_error_flag;
}


HYPRE_Int
hypre_BoomerAMGGetCumNnzAP( void     *data,
                              HYPRE_Real      *cum_nnz_AP )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *cum_nnz_AP = hypre_ParAMGDataCumNnzAP(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetResidual( void * data, hypre_ParVector ** resid )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *resid = hypre_ParAMGDataResidual( amg_data );
   return hypre_error_flag;
}
                            

HYPRE_Int
hypre_BoomerAMGGetRelResidualNorm( void     *data,
                                     HYPRE_Real   *rel_resid_norm )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   *rel_resid_norm = hypre_ParAMGDataRelativeResidualNorm(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetChebyOrder( void     *data,
                              HYPRE_Int       order)
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (order < 1)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataChebyOrder(amg_data) = order;

   return hypre_error_flag;
}
HYPRE_Int
hypre_BoomerAMGSetChebyFraction( void     *data,
                                 HYPRE_Real  ratio)
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (ratio <= 0.0 || ratio > 1.0 )
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataChebyFraction(amg_data) = ratio;

   return hypre_error_flag;
}
HYPRE_Int
hypre_BoomerAMGSetChebyEigEst( void     *data,
                              HYPRE_Int     cheby_eig_est)
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   if (cheby_eig_est < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataChebyEigEst(amg_data) = cheby_eig_est;

   return hypre_error_flag;
}
HYPRE_Int
hypre_BoomerAMGSetChebyVariant( void     *data,
                              HYPRE_Int     cheby_variant)
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataChebyVariant(amg_data) = cheby_variant;

   return hypre_error_flag;
}
HYPRE_Int
hypre_BoomerAMGSetChebyScale( void     *data,
                              HYPRE_Int     cheby_scale)
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;
 
   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   } 
   hypre_ParAMGDataChebyScale(amg_data) = cheby_scale;

   return hypre_error_flag;
}


HYPRE_Int
hypre_BoomerAMGSetAdditive( void *data,
                          HYPRE_Int   additive )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }

   hypre_ParAMGDataAdditive(amg_data) = additive;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetAdditive( void *data,
                             HYPRE_Int *  additive )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }

   *additive = hypre_ParAMGDataAdditive(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetMultAdditive( void *data,
                          HYPRE_Int   mult_additive )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }

   hypre_ParAMGDataMultAdditive(amg_data) = mult_additive;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetMultAdditive( void *data,
                             HYPRE_Int *  mult_additive )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }

   *mult_additive = hypre_ParAMGDataMultAdditive(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetSimple( void *data,
                          HYPRE_Int   simple )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }

   hypre_ParAMGDataSimple(amg_data) = simple;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGGetSimple( void *data,
                             HYPRE_Int *  simple )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }

   *simple = hypre_ParAMGDataSimple(amg_data);

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetAddLastLvl( void *data,
                          HYPRE_Int   add_last_lvl )
{
   hypre_ParAMGData  *amg_data = (hypre_ParAMGData*) data;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }

   hypre_ParAMGDataAddLastLvl(amg_data) = add_last_lvl;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetNonGalerkinTol( void   *data,
                            HYPRE_Real nongalerkin_tol)
{
   hypre_ParAMGData *amg_data = (hypre_ParAMGData*) data;
   HYPRE_Int i, max_num_levels;
   HYPRE_Real *nongal_tol_array;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }
   if (nongalerkin_tol < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }
   max_num_levels = hypre_ParAMGDataMaxLevels(amg_data);
   nongal_tol_array = hypre_ParAMGDataNonGalTolArray(amg_data);

   if (nongal_tol_array == NULL)
   {
      nongal_tol_array = hypre_CTAlloc(HYPRE_Real, max_num_levels);
      hypre_ParAMGDataNonGalTolArray(amg_data) = nongal_tol_array;
   }
   hypre_ParAMGDataNonGalerkinTol(amg_data) = nongalerkin_tol;

   for (i=0; i < max_num_levels; i++)
      nongal_tol_array[i] = nongalerkin_tol;

   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetLevelNonGalerkinTol( void   *data,
                            HYPRE_Real   nongalerkin_tol,
                            HYPRE_Int level)
{
   hypre_ParAMGData *amg_data = (hypre_ParAMGData*) data;
   HYPRE_Real *nongal_tol_array;
   HYPRE_Int max_num_levels;

   if (!amg_data)
   {
      hypre_error_in_arg(1);
      return hypre_error_flag;
   }

   if (nongalerkin_tol < 0)
   {
      hypre_error_in_arg(2);
      return hypre_error_flag;
   }

   nongal_tol_array = hypre_ParAMGDataNonGalTolArray(amg_data);
   max_num_levels = hypre_ParAMGDataMaxLevels(amg_data);

   if (nongal_tol_array == NULL)
   {
      nongal_tol_array = hypre_CTAlloc(HYPRE_Real, max_num_levels);
      hypre_ParAMGDataNonGalTolArray(amg_data) = nongal_tol_array;
   }

   if (level+1 > max_num_levels)
   {
      hypre_error_in_arg(3);
      return hypre_error_flag;
   }

   nongal_tol_array[level] = nongalerkin_tol;
   return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetNonGalerkTol( void   *data,
                            HYPRE_Int   nongalerk_num_tol,
                            HYPRE_Real *nongalerk_tol)
{
  hypre_ParAMGData *amg_data = (hypre_ParAMGData*) data;

  hypre_ParAMGDataNonGalerkNumTol(amg_data) = nongalerk_num_tol;
  hypre_ParAMGDataNonGalerkTol(amg_data) = nongalerk_tol;
  return hypre_error_flag;
}

HYPRE_Int
hypre_BoomerAMGSetRAP2( void   *data,
                            HYPRE_Int   rap2)
{
  hypre_ParAMGData *amg_data = (hypre_ParAMGData*) data;

  hypre_ParAMGDataRAP2(amg_data) = rap2;
  return hypre_error_flag;
}


HYPRE_Int
hypre_BoomerAMGSetKeepTranspose( void   *data,
                            HYPRE_Int   keepTranspose)
{
  hypre_ParAMGData *amg_data = (hypre_ParAMGData*) data;

  hypre_ParAMGDataKeepTranspose(amg_data) = keepTranspose;
  return hypre_error_flag;
}

